home *** CD-ROM | disk | FTP | other *** search
/ NetNews Offline 2 / NetNews Offline Volume 2.iso / news / comp / std / c / 762 < prev    next >
Text File  |  1996-08-06  |  5KB  |  106 lines

  1. Path: xylogics.com!not-for-mail
  2. From: carlson@xylogics.com (James Carlson)
  3. Newsgroups: comp.std.c
  4. Subject: Re: Q: char **foo, char *foo[], and char foo[][] ?
  5. Date: 18 Apr 1996 08:05:28 -0400
  6. Organization: Xylogics Incorporated
  7. Distribution: world
  8. Message-ID: <4l5b68$kg2@newhub.xylogics.com>
  9. References: <4l33ok$oo2@Sherlock.lectra.fr>
  10. Reply-To: carlson@xylogics.com
  11. NNTP-Posting-Host: newhub.xylogics.com
  12.  
  13.  
  14. In article <4l33ok$oo2@Sherlock.lectra.fr>, phil@rd.lectra.fr (Philippe Maurisset) writes:
  15. |> Considering the 3 following declarations:
  16. |> 
  17. |> 1 - char **foo;
  18. |> 2 - char *foo[];
  19. |> 3 - char foo[][];
  20. |> 
  21. [...non-working example deleted...]
  22. |> Can anybody help me ? Is it system-dependent ?
  23.  
  24. No, it's not system-dependent, but it is context-specific.
  25.  
  26. There are some rules you can follow.  When you define a simple array
  27. (all []'s, like foo[3][9]), you can refer to it in prototypes either as
  28. fully-dimensioned (all []'s with constant values, like foo[3][9]), or
  29. with the first dimension elided (all but first [] with constant, like
  30. foo[][9]), or even as a simple pointer (like *foo or foo[]), although
  31. the dimensioning will be lost and the elements will appear as a single-
  32. dimension array (27 elements in this case).  You may not refer to it as
  33. "*foo[]", either as an argument declarator or in an "extern" in a
  34. separate file.
  35.  
  36. When you create an array of pointers (like *foo[3][2]), you can refer to
  37. it in prototypes either as the same type of pointer (*foo[3][2] again),
  38. or with the first dimension elided (*foo[][2]), or even as a simple
  39. pointer (**foo), though, again, you drop back to single-dimension.
  40.  
  41. The pattern here is that the first set of brackets ([]) translate into
  42. one level of "*" in the function argument declaration, but additional
  43. levels of brackets do NOT add "*"s to the function argument.  Thus,
  44. char foo[1000] and char foo[10][10][10] are stored in exactly the same
  45. internal format, and can be referred to in a function argument list as
  46. foo[1000], foo[], foo[][10][10], foo[10][10][10], or *foo.
  47.  
  48. One more wrinkle to consider is that when declaring a variable, *foo is
  49. different from (and incompatible with) foo[], but when passed as an
  50. argument, they are identical.  Thus, when making "extern" statements to
  51. refer to a variable (rather than passing as an argument list), do not
  52. follow the above rules, but rather declare variable exactly as
  53. originally defined.  The only exception to that rule is that you may
  54. still elide the first dimension in an extern (like foo[][9]), but,
  55. again, you cannot choose to call this "*foo" in the extern.
  56.  
  57. Instead of trying to argue about the abstract types, let's instead look
  58. at a hypothetical example on an imaginary machine.
  59.  
  60.     char **var1;
  61.     char *var2[5];
  62.     char var3[3][2];
  63.  
  64. These three declarations could produce the following assembly code for
  65. our hypothetical machine (assuming 32-bit architecture, nice, simple
  66. system):
  67.  
  68.         .bss    var1,4        # single char** pointer, 4 bytes
  69.         .bss    var2,20        # five char* pointers, 20 bytes
  70.         .bss    var3,6        # array of 3x2 chars, 6 bytes
  71.  
  72. Note that these are extremely different.  The first case declares a
  73. single simple pointer, which happens to be a pointer-to-a-pointer.  The
  74. second declares a contiguous array of 5 pointers, each of which happens
  75. to be a pointer-to-a-char.  The last example just creates a block of 6
  76. bytes, no pointers.
  77.  
  78. Because the types are different, the compiler knows to generate
  79. different code for accessing each case.  Let's carry this a little
  80. further and fetch var3[2][1], var2[2][1], and var1[2][1].  These look
  81. like (two register machine, "ptr" and "acc"):
  82.  
  83.         move    (var3+5),acc    # move offset 2*2+1 into accum.
  84.  
  85.         move    (var2+8),ptr    # move offset 2*4 into pointer
  86.         move    1(ptr),acc    # move offset 1 into accumul.
  87.  
  88.         move    var3,ptr    # fetch var3 (pointer)
  89.         move    8(ptr),ptr    # move offset 2*4 into pointer
  90.         move    1(ptr),acc    # move offset 1 into accumul.
  91.  
  92. In the first case, the compiler uses the "var3" symbol as the location
  93. of the beginning of the array, and simply needs to offset out to the
  94. 6th location to fetch the desired character.  In the second case, the
  95. compiler can locate var2[2] immediately; it's the second element in the
  96. var2 array (pointers of 4 bytes each), but then it must use the value at
  97. that location as a pointer to the actual array of characters, and then
  98. fetch offset 1 from there.  In the last case, the compiler must fetch
  99. the contents of var3, treat it as a pointer to fetch the 2nd pointer
  100. value (again 4 bytes each), and then fetch offset 1 from that value.
  101.  
  102. -- 
  103. James Carlson <carlson@xylogics.com>            Tel:  +1 617 272 8140
  104. Annex Interface Development / Xylogics, Inc.          +1 800 225 3317
  105. 53 Third Avenue / Burlington MA  01803-4491     Fax:  +1 617 272 2618
  106.